#include "server.h"

TicToc g_tictoc;

/**
 * @msg: tcp连接管理器主线程
 * @param {void} 
 * @return: =0正常 <0连接错误
 */
int LinkControl::run()
{
    while(true)
    {
        if((this->connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1)
        {
            std::cerr << "accept socket error: " << strerror(errno) << std::endl;
            return -1;
        }
        std::cout << "++++++++++++++++ connect in ++++++++++++++++" << std::endl;
        g_tictoc.tic();
        while(true)
        {
            //接受数据 如果客户端没有发送 这里会一直阻塞（直到timeout）
            this->msg = this->recvData();
            if(this->msg.length() > 1)
            {
                g_tictoc.tic();
                if(this->msg == "exit")
                {
                    std::cout << "--------------- connect exit ---------------" << std::endl;
                    break;
                }
                if(this->msg != BEATFRAME)
                {
                    StuDataStruct l_stu_data;
                    std::string command = peekString(this->msg, COMMAND);
                    if(command == "LOGIN")
                    {
                        //普通用户登录
                        if(this->userAuth(this->msg, l_stu_data) > 0)
                        {
                            std::cout << "login confirm." << std::endl;
                            this->sendData("PASS");
                            
                            this->toDataBase(l_stu_data);
                        }
                        //超级用户登录
                        else if(this->userAuth(this->msg, l_stu_data) == 0)
                        {
                            std::cout << "super user login" << std::endl;
                            this->sendData("PASS");

                            this->toDataBaseSuper();
                        }
                        else{
                            std::cout << "login failure." << std::endl;
                            this->sendData("REJECT");
                        }
                    }
                    else
                    {
                        std::cout << msg << std::endl;
                    }
                }
            }
            //if(g_tictoc.toc() > 20)
            //{
            //    std::cout << "connect close: time out" <<std::endl;
            //    break;
            //}
        }
    }
    close(connfd);
    close(listenfd);
    return 0;
}

/**
 * @msg: 通过tcp协议接受数据 注意一旦调用该函数原线程会一直被阻塞直到读取到数据
 * @param {void} 
 * @return: std::string data_recv
 */
std::string LinkControl::recvData()
{
    std::string data_recv;
    //清空缓存
    memset(buff, 0, sizeof(buff));
    int n = recv(this->connfd, this->buff, MAXLINE, 0);
    //添加字符串空字符
    buff[n] = '\0';
    data_recv = buff;
    return data_recv;
}

/**
 * @msg: 通过tcp协议发送数据
 * @param {std::string data} 
 * @return: (bool) true: 发送成功；false: 发送失败
 */
bool LinkControl::sendData(std::string data)
{
    sprintf(this->buff, data.c_str());
    if(send(this->connfd, this->buff, strlen(buff) + 1, 0) > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/**
 * @msg: 通过登录验证后连接到数据库的子线程
 * @param {studentConfig& user(登录的用户信息)} 
 * @return: void
 */
void LinkControl::toDataBase(StuDataStruct stu_data)
{
    std::string l_msg;
    
    Student login_student(stu_data);

    while(true)
    {
        //接收数据
        l_msg = this->recvData();
        //丢弃心跳帧
        if(l_msg.length() > 1 && l_msg != BEATFRAME)
        {
            std::string command = peekString(l_msg, COMMAND);
            if(command == "LOGOUT")
            {
                //登出
                LOG::logPrint("user logout", LOG::MSG);
                break;
            }
            else if(command == "SEARCHSTU")
            {
                //查询个人信息
                LOG::logPrint("search request", LOG::MSG);
                this->sendData(DataBaseRW::zipData(login_student.getStuData()));
            }
            else if(command == "UPDATECONFIG")
            {
                //更新个人信息
                LOG::logPrint("write request", LOG::MSG);
                stu_data = login_student.getStuData();
                DataBaseRW::unzipData(l_msg, stu_data);
                login_student.updateConfig(stu_data);
                this->sendData("SUCCESS");
            }
            else if(command == "LOADSCORE")
            {
                //加载成绩数据
                LOG::logPrint("load scores data", LOG::MSG);
                this->sendData(DataBaseRW::zipScoreData(login_student.getStuData()));
            }
        }
    }
}

/**
 * @msg: 通过登录验证后连接到数据库的子线程(管理员用)
 * @param {void} 
 * @return: void
 */
void LinkControl::toDataBaseSuper()
{
    std::string l_msg;
    
    Student current_student;

    SubjectConfig l_subject_db;

    StuDataStruct stu_data;

    while(true)
    {
        //接收数据
        l_msg = this->recvData();
        //丢弃心跳帧
        if(l_msg.length() > 1 && l_msg != BEATFRAME)
        {
            std::string command = peekString(l_msg, COMMAND);
            if(command == "LOGOUT")
            {
                //登出
                LOG::logPrint("super user logout", LOG::MSG);
                break;
            }
            else if(command == "SEARCHSTU")
            {
                
                //通过学号查询用户信息 并打开对应数据文件
                LOG::logPrint("search request", LOG::MSG);
                if(g_search_db.searchStudent(peekString(l_msg, 1), 
                                             peekString(l_msg, 2), stu_data) == -1)
                {
                    this->sendData("no such student");
                }
                else
                {
                    LOG::logPrint("result found", LOG::MSG);
                    current_student.resetStudent(stu_data);
                    this->sendData(DataBaseRW::zipData(current_student.getStuData()));
                }
            }
            else if(command == "UPDATECONFIG")
            {
                //写入
                LOG::logPrint("write request", LOG::MSG);
                if(current_student.getStuData().id == "")
                {
                    this->sendData("FAILED");
                }
                else
                {
                    stu_data = current_student.getStuData();
                    DataBaseRW::unzipData(l_msg, stu_data);
                    current_student.updateConfig(stu_data);

                    this->sendData("SUCCESS");
                }
            }
            else if(command == "LOADSCORE")
            {
                //加载成绩数据
                LOG::logPrint("load scores data", LOG::MSG);
                this->sendData(DataBaseRW::zipScoreData(current_student.getStuData()));
            }
            else if(command == "ADDSTU")
            {
                //新建学生信息
                LOG::logPrint("add request", LOG::MSG);

                DataBaseRW::unzipData(l_msg, stu_data);
                current_student.resetStudent(stu_data);
                
                this->sendData("SUCCESS");
                LOG::logPrint("add succed", LOG::MSG);
            }
            else if(command == "SETSCORE")
            {
                LOG::logPrint("set score", LOG::MSG);

                stu_data = current_student.getStuData();
                DataBaseRW::unzipScoreData(l_msg, stu_data);
                current_student.updateScores(stu_data);
            }
            else if(command == "GETSUBJECT")
            {
                LOG::logPrint("pull subject", LOG::MSG);

                l_subject_db.setClass(l_msg);
                std::vector<SubjectScore> total_subject = l_subject_db.getTotalSubjects();
                this->sendData(DataBaseRW::zipSubjectData(total_subject));
            }
            else if(command == "SETSUBJECT")
            {
                LOG::logPrint("set subject", LOG::MSG);

                l_subject_db.addSubject(l_msg);
            }
            else if(command == "PULLALL")
            {
                LOG::logPrint("pull all data", LOG::MSG);

                Aclass current_class(l_msg);
                string send_msg = std::to_string(current_class.totalStudent()) + " " +
                                  std::to_string(current_class.totalSubject());
                this->sendData(send_msg);
                for(size_t i = 0; i < current_class.totalStudent(); i++)
                {
                    send_msg = current_class.getShortConfig(i) + " " + current_class.getZipMsg(i);
                    this->sendData(send_msg);
                    LOG::logPrint("send stu data: " + peekString(send_msg, 0), LOG::MSG);
                    usleep(10000);
                    l_msg = this->recvData();
                    if(l_msg != "ACK")
                    {
                        LOG::logPrint("network fault", LOG::ERROR);
                    }
                }
            }
        }
    }
}

/**
 * @msg: 登录验证
 * @param {std::string content, studentConfig& config(保存用户参数)} 
 * @return: -1错误 0超级用户权限 1普通用户
 */
int LinkControl::userAuth(std::string msg, StuDataStruct& stu_data)
{
    if(peekString(msg, 1) == "admin" && peekString(msg, 2) == "123456")
    {
        stu_data.name == "admin";
        return 0;
    }
    else
    {
        SearchList sl;
        sl.searchStudent("username", peekString(msg, 1), stu_data);
        if(peekString(msg, 2) == stu_data.password)
            return 1;
        else
            return -1;
    }
}

